package collection;

import java.util.Iterator;

public abstract class ACircularLinkedList<N extends ANode<T>, T> implements ICircularLinkedList<N, T>{
	
	N cursor = null;
	
	@Override
	public abstract N createNode(T element);
	
	@Override
	public N getCursor()
	{
		return this.cursor;
	}
	
	@Override
	public abstract N getPrev();
	
	@Override
	public abstract N getNext();
	
	@Override
	public abstract void moveToPrev();
	
	@Override
	public abstract void moveToNext();
	
	@Override
	public abstract void addBefore(N someNode);
	
	@Override
	public abstract void addAfter(N someNode);
	
	@Override
	public abstract N removeBefore();
	
	@Override
	public abstract N removeAfter();
	
	@Override
	public abstract void removeCursor();
	
	// need this method to abstract the toString() method
	protected abstract N getNext(N someNode);
	
	@Override
	public String toString()
	{
		if ( cursor == null )
		{
			return "[]";
		}
		
		N curNode = cursor;
		N startCursor = cursor;
		
		String retStr = "[";
		while (getNext(curNode) != startCursor)
		{
			retStr += curNode.toString() + ", ";
			curNode = getNext(curNode);
		}
		retStr += curNode.toString() + "]";

		return retStr;
	}

	@Override
	public Iterator<N> iterator() 
	{
		return new CircularLinkedListIterator<N>(this);
	}
	
	private class CircularLinkedListIterator<M extends ANode<T>> implements Iterator<M>{
		
		ACircularLinkedList<M, T> list = null;
		M curNode = null;
		
		CircularLinkedListIterator(ACircularLinkedList<M, T> list)
		{
			this.list = list;
			this.curNode = list.cursor;
		}
		
		@Override
		public boolean hasNext()
		{
			return (curNode != null);
		}
		
		@Override
		public M next()
		{
			M retNode = curNode;
			curNode = list.getNext(curNode);
			return retNode;
		}
		
		@Override
		public void remove()
		{
			throw new UnsupportedOperationException();
		}
	}
	
}
